local japi = require 'jass.japi'

local button = {}
setmetatable(button,button)

--- 存放所有按钮
button.allbuttons = {}

local mt = extends(ac.frame){}

--类型
mt.type = 'button'

--魔兽控件类型
mt._type = 'BUTTON'

--fdf名字
mt.fdf = "button"

--识别名称
mt._name = '按钮'

--按钮图标
mt.normal_image = nil 

--按钮禁用下的图标
mt.disabled = nil

--按钮按下状态图标
mt.pushedd = nil 

--指向反馈  (如果有这个字段且这个字段是panel or highlight 指向时将会自动显示)
mt.highlight = nil

--点击缩放效果
mt.ani_flag = false

--拖拽标志
mt.drag_flag = false 

--按钮快捷键
mt.hotkey = nil 

--按钮指令
mt.command = nil 

--按钮自定义参数
mt.params = nil 

function mt:__tostring()
    return string.format('[按钮]->%d',self.handle or 0)
end

--- 转换
function mt.convert(handle, is_simple, parent ,is_default)
    local control = button.allbuttons[handle]
    if control then 
        return control
    end 
    control = ac.frame.convert(handle, 'button', parent, is_default)
    control.simple_flag = is_simple
    button.allbuttons[handle] = control
    
    japi.RegisterFrameEvent(handle)
    return control
end

--- 创建控件
function mt.new(parent, image, x, y, w, h, ani_flag)
    local control = class.button:builder
    {
        parent = parent,
        normal_image = image,
        w = w,
        h = h,
        x = x,
        y = y,
        ani_flag = ani_flag,
    }
    return control
end

---初始化
function mt:init()
    if self.handle then return end 
    
    local handle = japi.CreateFrameByTagName(self._type,self._name,self.parent.handle,self.fdf,self._index)
    if not handle or handle == 0 then 
        log.error('创建button失败')
        ac.frame.remove(self)
        return  
    end

    self.handle = handle 


    local childs = japi.FrameGetChildlist(handle)
    
    self.child1 = class.panel.convert(childs[1], self)  --- 正常贴图
    self.child2 = class.panel.convert(childs[2], self)  --- 按下贴图
    self.child3 = class.panel.convert(childs[3], self)  --- 禁用贴图
    if self.pushedd then self:set_pushedd(self.pushedd) end
    if self.disabled then self:set_disabled(self.disabled) end

    self:set_normal_image(self.normal_image)
    self:set_alpha(self.alpha)
    self:set_width(self.w)
    self:set_height(self.h)
    self:set_position(self.x,self.y)
    self:set_ignore_trackevents(self.ignore_flag)
    self:set_enable(self.enable_flag)
    if self.show_flag then
        self.show_flag = false
        self:show()
    else 
        self.show_flag = true
        self:hide()
    end
    --- 注册监听器
    japi.RegisterFrameEvent(self.handle)

    button.allbuttons[handle] = self
    ac.frame.allframes[handle] = self 
    return self
end 

---删除控件
function mt:remove()
    if self.removed then return end
    if self:is_simple() then return end 
    button.allbuttons[self.handle] = nil
    ac.frame.remove(self)
end


--- 点击按钮
function mt:click()
    if self:is_enable() and self:is_show() then 
        japi.DzClickFrame(self.handle)
    end 
end

--- 按钮拥有点击缩放
function mt:has_ani()
    return self.ani_flag 
end

--- 按钮能否拖拽
function mt:is_drag( )
    return self.drag_flag
end

--- 设置贴图正常
function mt:set_normal_image(image)
    if not image then return end 
    self.normal_image = image
    self.child1:set_normal_image(image)
    if self.disabled == nil and self.child3 then 
        self.child3:set_normal_image(image)
    end
    if self.pushedd == nil and self.child2 then  
        self.child2:set_normal_image(image)
    end
end 

--- 设置禁用贴图
function mt:set_disabled(image)
    self.disabled = image
    if self.child3 then 
        self.child3:set_normal_image(image)
    end
end

--- 设置按下贴图
function mt:set_pushedd(image)
    self.pushedd = image
    if self.child2 then
        self.child2:set_normal_image(image)
    end
end

--- 设置高亮控件
--- @params highlight 子级控件
function mt:set_highlight(highlight)
    if type(highlight)=='string' then
        highlight = self:add_highlight(highlight)
    end
    local _type = highlight.type
    if (_type == 'highlight' or _type == 'panel') and highlight.handle then      
        highlight:hide()
        self.highlight = highlight
    end 
end 

--- 获取图像
--- @return string texture
function mt:get_normal_image()
    return self.normal_image
end

--- 重载方法
function mt:show()
    ac.frame.show(self)
    if self.handle == japi.GetMouseFocus() then 
        mt.events[2](self)
    end
end 

function mt:hide()
    if self.handle == japi.GetMouseFocus() then 
        mt.events[3](self)
    end
    ac.frame.hide(self)
end 

--- 重载方法
function mt:set_enable(flag)
    if (flag ~= true) and self.highlight and self.highlight.handle then 
        self.highlight:hide()
    end 
    return ac.frame.set_enable(self,flag)
end 


--- 所有被点击到的按钮存放
local allfocus = {}

--鼠标进入按钮和离开表
local button_keys_event_list = {}
local button_enter_event_list = {}
local button_leave_event_list = {}
local right_button_list = {}


--获取焦点上的按钮
local function get_focus_button()
    local handle = japi.GetMouseFocus()
    local focus  = button.allbuttons[handle]
    if focus==nil or focus._birth_index then
        local x,y = ac.hardware:get_mouse_pos()
        local max_index = 0
        focus = nil
        for id,button in pairs(button.allbuttons) do
            if button:is_absolute_show() and button:is_enable() and button:has_point(x, y) then 
                if button._birth_index > max_index then
                    focus = button
                    max_index = button._birth_index
                end
            end
        end
    end
    
    return focus
end

--- 事件注册
mt.events = {
    
    --默认点击去掉
    --[1] = function(self) 
    ['点击'] = function(self) 
        if self:is_simple() then 
            return 
        end 
        self:notify('on_button_clicked')
        if self.command and self.command ~= 'button' then 
            self:notify(('on_%s_clicked'):format(self.command),self.params)
        end 
        if self:is_show() and self.removed ~= true and self.mouse_clicked ~= true then 
            japi.FrameShow(self.handle,false)
            japi.FrameShow(self.handle,true)
            self.mouse_clicked = true
        end
    end,

    [2] = function(self) 
        if rawget(self,'highlight') then 
            self.highlight:show()
        end 

        self:notify('on_button_mouse_enter')
        
        if self.command and self.command ~= 'button' then 
            self:notify(('on_%s_mouse_enter'):format(self.command),self.params)
        end 
    end,

    [3] = function(self) 
        if rawget(self,'highlight') then 
            self.highlight:hide()
        end 
        
        self:notify('on_button_mouse_leave')
        ac.frame.remove_tooltip()
        
        if self.command and self.command ~= 'button' then 
            self:notify(('on_%s_mouse_leave'):format(self.command),self.params)
        end 
    end,
    
    --- 按钮自定义事件表
    --- 鼠标点击
    [-1] = function()
        local focus  = get_focus_button()
        if not focus or focus:is_simple() or not focus:is_enable() or focus.ignore_flag or not focus:is_show() then 
            return 
        end 
        
        if focus:has_ani() then 
            focus:set_relative_size(0.96,true)
        end 
        if focus:is_drag( ) then
            focus.drag_ready = true
            focus.drag_clock = os.clock()
        end
        focus.mouse_down = true
        focus.mouse_clicked = false
        table.insert(allfocus,focus)
        focus:notify('on_button_mouse_down')
    end,

    --- 鼠标释放
    [-2] = function()
        local target  = get_focus_button()
        for _,focus in ipairs(allfocus) do 
            if focus:has_ani() then 
                focus:set_relative_size(1,true)
            end 
            focus.mouse_down = false
            if focus:is_drag( ) and focus.drag_start then
                local x   , y   = button.drag_panel:get_real_position( )
                local w   , h   = button.drag_panel.w , button.drag_panel.h
                local tox , toy = ( x + w / 2 ) , ( y + w / 2 )
                focus:notify('on_button_drag_end' , target , tox , toy )
                focus.drag_start = false
            end
            -- if focus:is_show() and focus.removed ~= true and focus.mouse_clicked ~= true then 
            --     japi.FrameShow(focus.handle, false)
            --     japi.FrameShow(focus.handle, true)
            -- end
            focus:notify('on_button_mouse_up')
        end 

        --点击
        if target and target:has_mouse() then
            mt.events['点击'](target)
        end
        allfocus = {}
        button.drag_panel:hide( )
    end,

    --- 鼠标移动
    [-3] = function(_, x, y)
        local clock = os.clock()
        for _ , focus in ipairs( allfocus ) do
            if focus.mouse_down and focus:is_drag( ) then 
                if focus.drag_start then
                    local w   , h   = button.drag_panel.w , button.drag_panel.h
                    local tox , toy = ( x - w / 2 ) , ( y - h / 2 )
                    button.drag_panel:set_real_position( tox , toy )
                    focus:notify( 'on_button_drag' , x , y )
                elseif focus.drag_ready then 
                    if focus.mouse_down == true then 
                        if (clock - focus.drag_clock) > 0.15 then 
                            button.drag_panel:set_width( focus.w )
                            button.drag_panel:set_height( focus.h )
                            button.drag_panel:set_normal_image( focus.normal_image )
                            local x , y = focus:get_real_position( )
                            button.drag_panel:set_real_position( x , y )
                            button.drag_panel:show( )
                            focus.drag_ready = false
                            focus.drag_start = true
                            focus:notify( 'on_button_drag_start' , button.drag_panel )
                        end 
                    else 
                        focus.drag_ready = false
                    end 
                end 
            end
        end
    end,

    --- 界面绘制
    [-4] = function()
        if ac.game:is_active() then 
            button.active = true 
        else 
            if button.active then 
                button.active = false
                mt.events[-2]()
            end
        end
    end,

    --右键
    [-5] = function()
        local target  = get_focus_button()
        if target then
            target:notify('on_button_right_mousedown')
            table.insert(right_button_list,target)
        end
    end,
    [-6] = function()
        local target  = get_focus_button()
        for index,object in ipairs(right_button_list) do
            if object ~= target then 
                object:notify('on_button_right_mouseup')
            else
                object:notify('on_button_right_mouseup')
                target:notify('on_button_right_clicked')
            end
        end
        right_button_list = {}
    end,

    --- 键盘按下
    [-10] = function(_, code)
        local key = ac.message.keyboard[code] 
        if key == nil then
            return
        end
        if ac.game:is_chating() then 
            return 
        end
        if not button.ignore_active and not ac.game:is_active() then 
            return 
        end
        for _,btn in pairs(button.allbuttons) do
            if btn.hotkey == key and btn:is_enable() and btn:is_absolute_show() then
                btn:notify('on_button_key_down',key)
                button_keys_event_list[#button_keys_event_list + 1] = btn
            end
        end
        return true
    end,
    [-11] = function(_, code)
        local key = ac.message.keyboard[code] 
        if key == nil then
            return
        end
        if ac.game:is_chating() then 
            return 
        end
        if not button.ignore_active and not ac.game:is_active() then 
            return 
        end
        for _,btn in pairs(button_keys_event_list) do
            btn:set_relative_size(1,true)
            if btn.hotkey == key and btn:is_enable() and btn:is_absolute_show() then
                btn:notify('on_button_key_up',key)
                btn:notify('on_button_clicked',key)
            end
        end
        button_keys_event_list = {}
        return true
    end


}

ac.hardware:on("鼠标点击")(mt.events[-1])
ac.hardware:on("鼠标释放")(mt.events[-2])
ac.hardware:on("鼠标移动")(mt.events[-3])
ac.hardware:on("界面绘制")(mt.events[-4])
ac.hardware:on("鼠标右键点击")(mt.events[-5])
ac.hardware:on("鼠标右键释放")(mt.events[-6])
ac.message:on("键盘按下")(mt.events[-10])
ac.message:on("键盘弹起")(mt.events[-11])

button.drag_panel = class.panel:builder
{
    type         = 'panel' ,
    normal_image = [[]]    ,
    default      = true    ,
    alpha        = 0.75    ,
}
button.drag_panel:set_level(99)

class.button = mt


return mt